package site.isscloud.jt809;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.*;
import java.util.Date;

public class JT809Server {
    private static final int SERVER_PORT = 19765;
    private static final int GNSS_CENTER_ID = 1001;
    private static final int HEARTBEAT_INTERVAL = 30000; // 30秒心跳间隔
    private static final Map<String, Object> VALID_USERS = new HashMap<String, Object>();
    private static final ExecutorService executor = Executors.newCachedThreadPool();
    
    static {
        VALID_USERS.put("test_company", JT809Utils.md5_20("password123"));
    }
    
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(SERVER_PORT);
            System.out.println("JT809 Server started on port " + SERVER_PORT);
            
            while (true) {
                final Socket clientSocket = serverSocket.accept();
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        handleClient(clientSocket);
                    }
                });
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            executor.shutdown();
        }
    }
    
    private static void handleClient(final Socket clientSocket) {
        String clientId = clientSocket.getRemoteSocketAddress().toString();
        System.out.println("Client connected: " + clientId);
        
        InputStream in = null;
        OutputStream out = null;
        ScheduledExecutorService heartbeatExecutor = null;
        ScheduledFuture<?> heartbeatFuture = null;
        
        try {
            in = clientSocket.getInputStream();
            out = clientSocket.getOutputStream();
            final OutputStream finalOut = out;
            
            heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
            
            while (true) {
                final JT809Message message = JT809Utils.parseJT809Message(in);
                
                if (!message.verifyCrc()) {
                    System.err.println("CRC verification failed");
                    continue;
                }
                
                System.out.println("Received message: " + message);
                
                switch (message.getMsgId()) {
                    case 0x1001: // 登录请求
                        handleLoginRequest(message, out);
                        if (heartbeatFuture == null) {
                            heartbeatFuture = heartbeatExecutor.scheduleAtFixedRate(
                                new Runnable() {
                                    @Override
                                    public void run() {
                                        sendHeartbeat(finalOut);
                                    }
                                }, 
                                HEARTBEAT_INTERVAL, 
                                HEARTBEAT_INTERVAL, 
                                TimeUnit.MILLISECONDS
                            );
                        }
                        break;
                    case 0x1003: // 注销请求
                        handleLogoutRequest(message);
                        if (heartbeatFuture != null) {
                            heartbeatFuture.cancel(true);
                        }
                        return;
                    case 0x1200: // 车辆定位信息
                        handleVehicleLocation(message);
                        break;
                    case 0x1300: // 车辆管控指令
                        handleVehicleControlCommand(message);
                        break;
                    case 0x1400: // 报警信息上报
                        handleAlarmReport(message, out);
                        break;
                    case 0x1005: // 心跳
                        handleHeartbeat(message, out);
                        break;
                    case 0x1600: // 车辆静态信息
                        handleVehicleStaticInfo(message);
                        break;
                    case 0x1700: // 驾驶员信息
                        handleDriverInfo(message);
                        break;
                    case 0x1800: // 车辆运营数据交换
                        handleVehicleOperationData(message);
                        break;
                    case 0x1900: // 企业信息统计
                        handleCompanyStatisticsInfo(message);
                        break;
                    default:
                        System.err.println("Unknown message ID: " + message.getMsgId());
                }
            }
        } catch (IOException e) {
            System.out.println("Client disconnected: " + e.getMessage());
        } finally {
            if (heartbeatExecutor != null) {
                heartbeatExecutor.shutdown();
            }
            try {
                if (in != null) in.close();
                if (out != null) out.close();
                clientSocket.close();
                System.out.println("Connection closed for client: " + clientId);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    private static void handleLoginRequest(JT809Message message, OutputStream out) throws IOException {
        LoginRequest loginRequest = new LoginRequest(message.getMsgBody());
        System.out.println("Login request from: " + loginRequest.getUserId());
        
        boolean authenticated = VALID_USERS.containsKey(loginRequest.getUserId()) &&
                Arrays.equals((byte[]) VALID_USERS.get(loginRequest.getUserId()), loginRequest.getPassword());
        
        byte result = authenticated ? LoginResponse.SUCCESS : LoginResponse.FAILURE;
        int verifyCode = authenticated ? 12345678 : 0;
        
        LoginResponse response = new LoginResponse(result, verifyCode);
        JT809Message responseMessage = new JT809Message(
                0x1002, 
                message.getMsgSn(), 
                GNSS_CENTER_ID, 
                response.toByteArray()
        );
        
        out.write(responseMessage.toByteArray());
        out.flush();
        System.out.println("Sent login response: " + (authenticated ? "SUCCESS" : "FAILURE"));
    }
    
    private static void handleLogoutRequest(JT809Message message) {
        LogoutRequest logoutRequest = new LogoutRequest(message.getMsgBody());
        System.out.println("Received logout request from platform: " + logoutRequest.getPlatformId());
    }
    
    private static void handleHeartbeat(JT809Message message, OutputStream out) throws IOException {
        System.out.println("Received heartbeat from client");
    }
    
    private static void sendHeartbeat(OutputStream out) {
        try {
            JT809Message heartbeat = new JT809Message(
                    0x1005, 
                    (int) (System.currentTimeMillis() % Integer.MAX_VALUE), 
                    GNSS_CENTER_ID, 
                    new byte[0]
            );
            out.write(heartbeat.toByteArray());
            out.flush();
            System.out.println("Sent heartbeat to client");
        } catch (IOException e) {
            System.err.println("Failed to send heartbeat: " + e.getMessage());
        }
    }
    
    private static void handleVehicleLocation(JT809Message message) {
        try {
            VehicleLocationMessage location = VehicleLocationMessage.fromByteArray(message.getMsgBody());
            System.out.println("Received vehicle location:");
            System.out.println(location);
        } catch (Exception e) {
            System.err.println("Error parsing vehicle location: " + e.getMessage());
        }
    }

    private static void handleVehicleControlCommand(JT809Message message) {
        try {
            VehicleControlCommand command = VehicleControlCommand.fromByteArray(message.getMsgBody());
            System.out.println("Received vehicle control command:");
            System.out.println(command);
        } catch (Exception e) {
            System.err.println("Error parsing vehicle control command: " + e.getMessage());
        }
    }
    
    private static void handleVehicleStaticInfo(JT809Message message) {
        try {
            VehicleStaticInfo info = VehicleStaticInfo.fromByteArray(message.getMsgBody());
            System.out.println("Received vehicle static info:");
            System.out.println("Plate No: " + info.getPlateNo());
            System.out.println("Plate Color: " + info.getPlateColor());
            System.out.println("Vehicle Type: " + info.getVehicleType());
            System.out.println("Company: " + info.getCompany());
            System.out.println("VIN: " + info.getVin());
        } catch (Exception e) {
            System.err.println("Error parsing vehicle static info: " + e.getMessage());
        }
    }
    
    private static void handleDriverInfo(JT809Message message) {
        try {
            DriverInfo info = DriverInfo.fromByteArray(message.getMsgBody());
            System.out.println("Received driver info:");
            System.out.println("Name: " + info.getName());
            System.out.println("ID Card: " + info.getIdCard());
            System.out.println("Qualification No: " + info.getQualificationNo());
            System.out.println("Company: " + info.getCompany());
        } catch (Exception e) {
            System.err.println("Error parsing driver info: " + e.getMessage());
        }
    }
    
    private static void handleAlarmReport(JT809Message message, OutputStream out) throws IOException {
        try {
            AlarmInfo alarmInfo = AlarmInfo.fromByteArray(message.getMsgBody());
            System.out.println("Received alarm report from client:");
            System.out.println("Vehicle: " + alarmInfo.getVehicleNo());
            System.out.println("Alarm Type: " + (alarmInfo.getAlarmType() == 0x01 ? "Over speed" : "Fatigue driving"));
            System.out.println("Time: " + new Date(alarmInfo.getAlarmTime()));
            System.out.println("Location: " + alarmInfo.getLongitude() + "," + alarmInfo.getLatitude());
            System.out.println("Speed: " + alarmInfo.getSpeed() + "km/h");
            
            // 模拟处理报警信息
            String[] actions = {"已通知交警处理", "已发送警告信息", "已记录违章", "已联系司机"};
            String action = actions[(int)(Math.random() * actions.length)];
            int resultType = Math.random() > 0.5 ? 0x01 : 0x02;
            
            AlarmResult result = new AlarmResult(
                alarmInfo.getVehicleNo(),
                alarmInfo.getVehicleColor(),
                alarmInfo.getAlarmTime(),
                alarmInfo.getAlarmType(),
                resultType,
                action
            );
            
            JT809Message response = new JT809Message(
                0x1401,
                message.getMsgSn(),
                GNSS_CENTER_ID,
                result.toByteArray()
            );
            
            out.write(response.toByteArray());
            out.flush();
            System.out.println("Sent alarm result to client: " + result);
        } catch (Exception e) {
            System.err.println("Error processing alarm report: " + e.getMessage());
        }
    }

    // 添加新的处理方法
    private static void handleVehicleOperationData(JT809Message message) {
        try {
            VehicleOperationData data = VehicleOperationData.fromByteArray(message.getMsgBody());
            System.out.println("Received vehicle operation data:");
            System.out.println("Vehicle: " + data.getVehicleNo());
            System.out.println("Period: " + getPeriodTypeDesc(data.getPeriodType()) + 
                            " (" + data.getStartTime() + " to " + data.getEndTime() + ")");
            System.out.println("Mileage: " + data.getOperationMileage() + " km");
            System.out.println("Violations: " + data.getViolationCount());
            System.out.println("Fuel Consumption: " + data.getFuelConsumption() + " L");
            
            // 这里可以添加数据存储或处理逻辑
        } catch (Exception e) {
            System.err.println("Error parsing vehicle operation data: " + e.getMessage());
        }
    }

    private static void handleCompanyStatisticsInfo(JT809Message message) {
        try {
            CompanyStatisticsInfo info = CompanyStatisticsInfo.fromByteArray(message.getMsgBody());
            System.out.println("Received company statistics info:");
            System.out.println("Company: " + info.getCompanyName() + " (" + info.getCompanyId() + ")");
            System.out.println("Vehicles: " + info.getOnlineVehicles() + "/" + info.getTotalVehicles() + " online");
            System.out.println("Drivers: " + info.getTotalDrivers());
            System.out.println("Compliance Rate: " + (info.getComplianceRate() * 100) + "%");
            
            // 这里可以添加数据存储或处理逻辑
        } catch (Exception e) {
            System.err.println("Error parsing company statistics info: " + e.getMessage());
        }
    }

    private static String getPeriodTypeDesc(byte periodType) {
        switch (periodType) {
            case 1: return "Daily";
            case 2: return "Monthly";
            case 3: return "Yearly";
            default: return "Unknown";
        }
    }
}
